﻿/********
* 
* 
*  Description:
*  Create By kain.hong at 8/9/2010 4:52:30 PM
*  
*
*  Revision History:
*  Date                  Who                 What
*  
* 
*/
#region namespace

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.Diagnostics;
using System.Security;

#endregion


namespace Cherry.Agile.ServiceModel.Interceptor
{
    [AttributeUsage(AttributeTargets.Class)]
    internal class EndpointInterceptorAttribute : Attribute,IEndpointBehavior 
    {
        /// <summary>
        /// 是否支持双向消息头存储
        /// </summary>
        public bool IsBidirectional { get; set; }

        public PolicyLevel PolicyLevel { get; set; }
        /// <summary>
        /// 构造函数
        /// </summary>
        public EndpointInterceptorAttribute():this(false)
        { 

        }
        public EndpointInterceptorAttribute(bool isBidirectional):this(isBidirectional, PolicyLevel.Enterprise)
        {

        }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="isBidirectional">是否支持双向消息头存储</param>
        public EndpointInterceptorAttribute(bool isBidirectional, PolicyLevel policyLevel)
        {
            IsBidirectional = isBidirectional;
            PolicyLevel = policyLevel;
        }

        void IEndpointBehavior.AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
           
        }

        void IEndpointBehavior.ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
            var t = clientRuntime.ContractClientType;
            var level = GetPolicyLevel(t);
            if (this.PolicyLevel < level)
                level = this.PolicyLevel;

            clientRuntime.MessageInspectors.Add(new ClientMessageInspector(IsBidirectional, level));
            Trace.TraceInformation("EndpointInterceptorAttribute\tapply message inspector into endpoint:" + endpoint.Address);

            foreach (var op in clientRuntime.Operations)
            {
                op.ParameterInspectors.Add(new Cherry.Agile.ServiceModel.PaginationParameterInspector());
            }
        }

        static System.Collections.Concurrent.ConcurrentDictionary<int, PolicyLevel> _PolicyLevelCache = new System.Collections.Concurrent.ConcurrentDictionary<int, PolicyLevel>();
        private static PolicyLevel GetPolicyLevel(Type type)
        {

            PolicyLevel level = PolicyLevel.Enterprise;
            if (!_PolicyLevelCache.TryGetValue(type.GetHashCode(), out level))
            {
                var atr = type.GetCustomAttributes(typeof(ServiceContractInterceptorAttribute), false).FirstOrDefault() as ServiceContractInterceptorAttribute;
                
                if (atr != null)
                {
                    level = atr.PolicyLevel;
                }
                _PolicyLevelCache.TryAdd(type.GetHashCode(), level);
            }
            return level;
        }

        void IEndpointBehavior.ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {
            //endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new MessageInspector(endpoint.Contract.ContractType));
            foreach (var operation in endpointDispatcher.DispatchRuntime.Operations)
            {
                Trace.TraceInformation("EndpointInterceptorAttribute\tapply call context inistializer into endpoint:" + endpoint.Address);
                operation.CallContextInitializers.Add(new ContextReceivalCallContextInitializer(this.IsBidirectional,this.PolicyLevel));
            }
        }

        void IEndpointBehavior.Validate(ServiceEndpoint endpoint)
        {
         
        }
    }
}
